﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.ComponentModel;

namespace iPdf
{
    class ItemRetrievor
    {
        #region Enum

        public enum TataSearchOption
        {
            None = 0,
            SearchSubFolders = 1,
            SearchHiddenFiles = 2
        }
        #endregion

        #region Fields
        /// <summary>
        /// Fields
        /// </summary>
        private List<FileFormat> formats;
        private ProgressDialog progressDialog;
        public delegate void FindingComplete(string[] items);
        private FindingComplete OnComplete;
        public delegate void FoundItem(string item);
        private FoundItem OnItemFound;

        private BackgroundWorker worker;
        private TataSearchOption searchOption = 0;

        private static bool busy = false;
        private Queue<string> directoryQueue = new Queue<string>();
        private bool userCancelled = false;
        #endregion

        #region Properties

        public List<FileFormat> Formats
        {
            get
            {
                return formats;
            }
            set
            {
                formats = value;
            }
        }


        public ProgressDialog ProgressDialog
        {
            get
            {
                return progressDialog;
            }
        }

        public static bool Busy
        {
            get
            {
                return busy;
            }
        }

        #endregion

        #region Ctor
        /// <summary>
        /// Ctor
        /// </summary>
        public ItemRetrievor()
            : this( FileFormat.PdfFormat )
        {
        }

        public ItemRetrievor(FileFormat fmt)
            : this(fmt, null, null)
        {
        }

        public ItemRetrievor(FileFormat fmt, 
            FindingComplete onComplete,
            FoundItem onItemFound)
                : this( new FileFormat[]{fmt}, onComplete, onItemFound)
        {
        }

        public ItemRetrievor(FileFormat[] fmts,
            FindingComplete onComplete,
            FoundItem onItemFound)
        {
            formats = new List<FileFormat>();
            formats.AddRange(fmts);
            this.OnComplete = onComplete;
            this.OnItemFound = onItemFound;

            worker = new BackgroundWorker();
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnFindingComplete);
            worker.DoWork += new DoWorkEventHandler(FindInFolder);
            worker.WorkerSupportsCancellation = true;
            progressDialog = new ProgressDialog();
            progressDialog.UserCancelled += new ProgressDialog.CancelCallback(CancelSearching);
        }

        #endregion

        #region Methods

        private void FindFilesInFolder(DirectoryInfo dirInfo)
        {
            if ( (searchOption & TataSearchOption.SearchSubFolders) != 0)
            {
                //get the items from the sub directories
                try
                {
                    DirectoryInfo[] subDirs = dirInfo.GetDirectories();
                    foreach (DirectoryInfo subDir in subDirs)
                    {
                        if (worker.CancellationPending == true)
                        {
                            return;
                        }
                        FindFilesInFolder(subDir);
                    }
                }
                catch
                {
                    //ignore it
                }
            }

            //get items form the current directory
            foreach (FileFormat format in formats)
            {
                Collection<string> wildcards = format.Wildcards;
                foreach (string wildcard in wildcards)
                {
                    try
                    {
                        if (worker.CancellationPending == true)
                        {
                            return;
                        }
                        FileInfo[] filesInFolder = dirInfo.GetFiles(wildcard);
                        foreach (FileInfo file in filesInFolder)
                        {
                            FileAttributes attr = file.Attributes;
                            if ((attr & FileAttributes.Normal) > 0 ||
                                (
                                (attr & FileAttributes.Compressed) == 0 &&
                                (attr & FileAttributes.Device) == 0 &&
                                (attr & FileAttributes.Encrypted) == 0 &&
                               (  (attr & FileAttributes.Hidden) == 0 || 
                               (searchOption & TataSearchOption.SearchHiddenFiles) != 0)
                                &&
                                (attr & FileAttributes.Offline) == 0 &&
                                (attr & FileAttributes.SparseFile) == 0 &&
                                (attr & FileAttributes.System) == 0 &&
                                (attr & FileAttributes.Temporary) == 0
                                ))
                            {
                                if (OnItemFound != null)
                                {
                                    OnItemFound(file.FullName);
                                }
                            }
                        }
                    }
                    catch
                    {
                        //ignore it
                    }
                }
            }
        }

        private void FindInFolder(Object sender, DoWorkEventArgs e)
        {
            string path = (string)e.Argument;
            DirectoryInfo dirInfo = new DirectoryInfo(path);

            FindFilesInFolder(dirInfo);
        }

        private void CancelSearching()
        {
            worker.CancelAsync();

            userCancelled = true;
        }

        public void RetrieveFiles()
        {
            OpenFileDialog fileOpen = Helper.CreateOpenFileDialog(formats.ToArray(), true);

            if (fileOpen.ShowDialog() == DialogResult.OK && OnComplete != null)
            {
                OnComplete(fileOpen.FileNames);
            }
        }

        public void RetrieveFolder(TataSearchOption searchOption)
        {
            RetrieveFolders(searchOption, null);
        }


        public void RetrieveFolders(TataSearchOption searchOption, string[] directories)
        {
            if (directories == null || directories.Length == 0)
            {
                FolderBrowserDialog folderBrowser = new FolderBrowserDialog();
                folderBrowser.ShowNewFolderButton = false;
                folderBrowser.SelectedPath = Global.MainWindow.DefaultOutputFolder;
                if (folderBrowser.ShowDialog() == DialogResult.OK)
                {
                    directories = new string[]{ folderBrowser.SelectedPath };
                }
                else
                {
                    return;
                }
            }

            foreach (string directory in directories)
            {
                directoryQueue.Enqueue(directory);
            }

            StartSearching(searchOption, directoryQueue.Dequeue());
        }

        private void StartSearching(TataSearchOption searchOption, string directory)
        {
            Global.MainWindow.EnableRibbon(false);
            progressDialog.Show(Global.MainWindow);
            this.searchOption = searchOption;

            worker.RunWorkerAsync(directory);
            busy = true;
        }

        private void OnFindingComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            if (directoryQueue.Count != 0 && !userCancelled)
            {
                worker.RunWorkerAsync(directoryQueue.Dequeue());
            }
            else
            {
                if (OnComplete != null)
                {
                    OnComplete(null);
                }

                progressDialog.Close();
                busy = false;
                userCancelled = false;
                directoryQueue.Clear();
            }
        }

        #endregion
    }
}
